﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using iNet.Tasks;

namespace iNet.Media.Imaging.Filters
{
	/// <summary>
	/// 單一色調濾鏡工作。
	/// </summary>
	public unsafe class MonoToneFilterTask : BitmapImageFilterTask
	{
		#region 欄位
		Color _ReferenceColor;
        #endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 MonoToneFilterTask 執行個體。
		/// </summary>
		public MonoToneFilterTask()
		{ }
		/// <summary>
		/// 初始化新的 MonoToneFilterTask 執行個體。
		/// </summary>
		/// <param name="sourceImage">來源點陣圖。</param>
		public MonoToneFilterTask(IBitmapImage sourceImage)
			: base(sourceImage)
		{ }
		/// <summary>
		/// 初始化新的 MonoToneFilterTask 執行個體。
		/// </summary>
		/// <param name="sourceImage">來源點陣圖。</param>
		/// <param name="refColor">參考色調。</param>
		public MonoToneFilterTask(IBitmapImage sourceImage, Color refColor)
			: base(sourceImage)
		{
			_ReferenceColor = refColor;
		}
        #endregion
		#region ApplyFilter
		/// <summary>
		/// 套用濾鏡至點陣圖。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="filterData">套用濾鏡所需的資料。</param>
		/// <returns>True 表示濾鏡套用成功，False 表示失敗。</returns>
		protected override bool ApplyFilter(TaskVersion version, BitmapImageFilterData filterData)
		{
			//取得資料
			Color referenceColor;
			if (!this.ReadValue<Color>(version, ref _ReferenceColor, out referenceColor))
				return true;

			//取得色調
			int rgbSum = (referenceColor.R + referenceColor.G + referenceColor.B);
			double rRatio = ((double)referenceColor.R / rgbSum);
			double gRatio = ((double)referenceColor.G / rgbSum);
			double bRatio = ((double)referenceColor.B / rgbSum);
			double intensityRatio = ((referenceColor.R + referenceColor.G + referenceColor.B) / 765.0);

			//套用濾鏡
			bool is16BitsColor = filterData.Is16BitsColor;
			int bytesPerPixel = filterData.BytesPerPixel;
			int width = filterData.PixelWidth;
			int height = filterData.PixelHeight;
			int stride = filterData.Stride;
			byte* srcLinePixels = (byte*)filterData.SourcePixelBuffer;
			byte* resultLinePixels = (byte*)filterData.ResultPixelBuffer;
			for (int y = 0; y < height; ++y, srcLinePixels += stride, resultLinePixels += stride)
			{
				byte* srcPixel = srcLinePixels;
				byte* resultPixel = resultLinePixels;
				for (int x = 0; x < width; ++x, srcPixel += bytesPerPixel, resultPixel += bytesPerPixel)
				{
					if (!is16BitsColor)
					{
						int r = srcPixel[2];
						int g = srcPixel[1];
						int b = srcPixel[0];
						double sum = ((r + g + b) * intensityRatio);
						r = (int)(sum * rRatio);
						g = (int)(sum * gRatio);
						b = (int)(sum * bRatio);
						resultPixel[2] = (r <= 255 ? (byte)r : (byte)255);
						resultPixel[1] = (g <= 255 ? (byte)g : (byte)255);
						resultPixel[0] = (b <= 255 ? (byte)b : (byte)255);
					}
					else
					{
						int r = *(ushort*)(srcPixel + 4);
						int g = *(ushort*)(srcPixel + 2);
						int b = *(ushort*)(srcPixel);
						double sum = ((r + g + b) * intensityRatio);
						r = (int)(sum * rRatio);
						g = (int)(sum * gRatio);
						b = (int)(sum * bRatio);
						*(ushort*)(resultPixel + 4) = (r <= 65535 ? (ushort)r : (ushort)65535);
						*(ushort*)(resultPixel + 2) = (g <= 65535 ? (ushort)g : (ushort)65535);
						*(ushort*)(resultPixel) = (b <= 65535 ? (ushort)b : (ushort)65535);
					}
				}
				if (this.IsCanceling)
					break;
				this.ReportProgress(version, ((y + 1) * 100.0 / height));
			}

			//完成
			return true;
		}
        #endregion
		#region ReferenceColor
		/// <summary>
		/// 取得或設定參考色，濾鏡將使用此顏色的色調套用至點陣圖。
		/// </summary>
		public Color ReferenceColor
		{
			get
			{
				return _ReferenceColor;
			}
			set
			{
				this.SetInitializingParameter<Color>(ref _ReferenceColor, value);
			}
		}
        #endregion
	}
}
